package com.yulan.bankback.xxlJob;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yulan.bankback.entity.event.AttackEvent;
import com.yulan.bankback.entity.event.LoginEvent;
import com.yulan.bankback.entity.model.admin.*;
import com.yulan.bankback.entity.model.admin.systemExperience.UserUseTime;
import com.yulan.bankback.entity.model.admin.systemSafe.*;
import com.yulan.bankback.entity.model.bank.BankUser;
import com.yulan.bankback.entity.model.bank.UserBalance;
import com.yulan.bankback.entity.model.bank.UserCapitalFlow;
import com.yulan.bankback.entity.model.bank.UserMostLoginPlace;
import com.yulan.bankback.mapper.admin.*;
import com.yulan.bankback.mapper.admin.systemExprience.UserUseTimeMapper;
import com.yulan.bankback.mapper.admin.systemSafe.*;
import com.yulan.bankback.mapper.admin.webAttack.AttackEventMapper;
import com.yulan.bankback.mapper.bank.*;
import com.yulan.bankback.service.bank.RedisService;
import com.yulan.bankback.service.ip.IpService;
import lombok.extern.slf4j.Slf4j;
import net.ipip.ipdb.IPFormatException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class BankAdminJobHandler {

    @Resource
    private UserCapitalFlowMapper userCapitalFlowMapper;

    @Resource
    private MoneyFlowMapper moneyFlowMapper;

    @Resource
    private AttackEventMapper attackEventMapper;

    @Resource
    private AttackTypeCountMapper attackTypeCountMapper;


    @Resource
    private MonthAttackMapper monthAttackMapper;


    @Autowired
    private IpService ipService;

    @Resource
    private CityAttackCountMapper cityAttackCountMapper;


    @Resource
    private LoginEventMapper loginEventMapper;

    @Resource
    private UserMostLoginPlaceMapper userMostLoginPlaceMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ViolationUserMapper violationUserMapper;

    @Autowired
    private EverydayVUCountMapper everydayVUCountMapper;


    @Autowired
    private KindUserMapper kindUserMapper;

    @Autowired
    private BlackUserPromoteMapper blackUserPromoteMapper;

    @Resource
    private UserUseTimeMapper userUseTimeMapper;

    @Resource
    private ViolationUserTypeMapper violationUserTypeMapper;

    @Resource
    private BankUserMapper bankUserMapper;

    @Resource
    private RemoteLoginEventMapper remoteLoginEventMapper;


    @Resource
    private RemoteLoginFreqMapper remoteLoginFreqMapper;

    @Resource
    private MonthRemoteLoginMapper monthRemoteLoginMapper;

    @Resource
    private SensitiveTradingMapper sensitiveTradingMapper;

    @Resource
    private UserBalanceMapper userBalanceMapper;

    private static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd");

    private static final SimpleDateFormat formatter3 = new SimpleDateFormat("MM-dd");


    private int interval = 1000;

    /**
     *
     * 聚合每日资金流
     */
    @XxlJob("moneyFlowGroupJobHandler")
    public ReturnT<String> executeMoneyGroup(String s) throws Exception {
        log.info("handle money flow group job");
        Date curDate = new Date(System.currentTimeMillis());
        String cur = DateUtil.format(curDate, "yyyy-MM-dd");
        QueryWrapper<UserCapitalFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("time", cur);

        List<UserCapitalFlow> userCapitalFlows = userCapitalFlowMapper.selectList(queryWrapper);
        Double todayMoney = userCapitalFlows.stream()
                .mapToDouble(UserCapitalFlow::getMoney)
                .sum();

        MoneyFlow todayMoneyFlow = moneyFlowMapper.selectOne(
                new QueryWrapper<MoneyFlow>().eq("time", cur));
        if(todayMoneyFlow == null){
            moneyFlowMapper.insert(new MoneyFlow(new Date(), todayMoney, cur));
        }else if(!todayMoneyFlow.getMoney().equals(todayMoney)){
            todayMoneyFlow.setMoney(todayMoney);
            moneyFlowMapper.updateById(todayMoneyFlow);
        }else{
            //不需要处理
        }

        log.info("已完成资金流聚合操作");
        return ReturnT.SUCCESS;
    }

    /**
     *
     * 聚合攻击类型
     */
    @XxlJob("attackTypeGroupJobHandler")
    public ReturnT<String> executeAttackGroup(String s) throws Exception {
        Date curDate = new Date(System.currentTimeMillis());
        String cur = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        List<AttackEvent> attackEvents = attackEventMapper.selectList(
                new QueryWrapper<AttackEvent>().gt("create_time", cur));

        List<AttackTypeCount> attackTypeCounts = attackTypeCountMapper.selectList(
                new QueryWrapper<>());

        Map<String, AttackTypeCount> typeMap = attackTypeCounts.stream()
                .collect(Collectors.toMap(AttackTypeCount::getAttackType, a -> a,(k1, k2)->k1));
        attackEvents.forEach(item ->{
            AttackTypeCount attackTypeCount = typeMap.get(item.getType());
            if(attackTypeCount == null){
                typeMap.put(item.getType(), new AttackTypeCount(item.getType(), 1));
            }else{
                attackTypeCount.setCount(attackTypeCount.getCount() + 1);
                typeMap.put(item.getType(),attackTypeCount);
            }
        });

        for(String type : typeMap.keySet()){
            attackTypeCountMapper.updateById(typeMap.get(type));
        }

        log.info("已完成攻击数量聚合操作");

        return ReturnT.SUCCESS;
    }


    /**
     * 聚合每个月攻击次数
     *
     */
    @XxlJob("attackCountGroupJobHandler")
    public ReturnT<String> executeAttackCountGroup(String s) throws Exception {

        Date curDate = new Date(System.currentTimeMillis());
        //当月第一天
        String cur = DateUtil.format(curDate, "yyyy-MM-01 00:00:00");
        Integer count = attackEventMapper.selectCount(new
                QueryWrapper<AttackEvent>().gt("create_time", cur));
        int year = DateUtil.year(curDate);
        int month = DateUtil.month(curDate) + 1;

        MonthAttack monthAttack = monthAttackMapper.selectOne(
                new QueryWrapper<MonthAttack>()
                        .eq("year", year)
                        .eq("month", month));
        if(monthAttack == null){
            monthAttack = new MonthAttack(year, month, count);
            monthAttackMapper.insert(monthAttack);
        }else{
            monthAttack.setCount(count);
            monthAttackMapper.updateById(monthAttack);
        }

        log.info("已完成攻击次数聚合任务");
        return ReturnT.SUCCESS;
    }

    @XxlJob("cityAttackCountGroupJobHandler")
    public ReturnT<String> executeCityAttackCountGroup(String s) throws Exception {
        Date curDate = new Date(System.currentTimeMillis());
        //当月第一天
        String curDay = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        List<AttackEvent> todayAttackEvents = attackEventMapper.selectList(
                new QueryWrapper<AttackEvent>().gt("create_time", curDay));

        Map<String, Integer> todayCityAttackCountMap = new HashMap<>();
        todayAttackEvents.forEach(item -> {
            try {
                String city = ipService.findCityByIp(item.getIp()).getCityName();
                todayCityAttackCountMap.put(city,
                        todayCityAttackCountMap.getOrDefault(city, 0) + 1);
            } catch (IPFormatException | IOException e) {
                e.printStackTrace();
            }
        });

        List<CityAttackCount> curCityAttackCount
                = cityAttackCountMapper.selectList(new QueryWrapper<>());

        //存放已经存在的城市
        Map<String, CityAttackCount> curCityAttackCountMap = curCityAttackCount.stream()
                .collect(Collectors.toMap(
                        CityAttackCount::getCity, a -> a,(k1,k2)->k1)
                );
        //存放还没有的城市
        Map<String, CityAttackCount> newCityMap = new HashMap<>();

        for(String city : todayCityAttackCountMap.keySet()){
            CityAttackCount attackCount = curCityAttackCountMap.get(city);

            if(attackCount == null){//存放到另外一张hash表
                if(newCityMap.get(city) == null){
                    newCityMap.put(city, new CityAttackCount(city, todayCityAttackCountMap.get(city)));
                }
            }else{
                attackCount.setCount(attackCount.getCount() + 1);
                curCityAttackCountMap.put(city, attackCount);
            }
        }


        for(String city : curCityAttackCountMap.keySet()){
            cityAttackCountMapper.updateById(curCityAttackCountMap.get(city));
        }

        for(String city : newCityMap.keySet()){
            cityAttackCountMapper.insert(newCityMap.get(city));
        }

        log.info("已完成网络攻击分布数量聚合");

        return ReturnT.SUCCESS;
    }


    /**
     * 定时计算用户常登陆地
     */
    @XxlJob("loginPlaceGroupJobHandler")
    public ReturnT<String> executeLoginCityGroup(String s) throws Exception {
        Set<String> uidSet= new HashSet<>();
        for(int i = 0; i < interval && redisService.listSize("user_id_list") > 0; i++){
            uidSet.add(redisService.rpop("user_id_list"));
        }

        uidSet.forEach(uid -> {
            List<LoginEvent> lastMonthLoginEvent = loginEventMapper.getLastMonthEvent(uid);
            Map<String, Long> cityCount = lastMonthLoginEvent.stream()
                    .collect(Collectors.groupingBy(LoginEvent::getLoginPlace, Collectors.counting()));

            PriorityQueue<String> queue = new PriorityQueue<>((a, b) -> (int) (cityCount.get(b) - cityCount.get(a)));
            queue.addAll(cityCount.keySet());
            int k = 3;
            List<String> mostThreeCity = new ArrayList<>();
            while(k > 0 && !queue.isEmpty()){
                mostThreeCity.add(queue.poll());
                k--;
            }
            StringBuilder citys = new StringBuilder();
            mostThreeCity.forEach(city ->{
                citys.append(city).append(",");

            });
            citys.deleteCharAt(citys.lastIndexOf(","));
            UserMostLoginPlace place = new UserMostLoginPlace();
            place.setUid(uid);
            place.setLoginPlaces(citys.toString());
            userMostLoginPlaceMapper.insert(place);
        });

        log.info("已完成用户常登陆地聚合定时任务");
        return ReturnT.SUCCESS;
    }


    @XxlJob("violationUserGroupJobHandler")
    public ReturnT<String> executeViolationUserGroup(String s) throws Exception{
        Date curDate = new Date(System.currentTimeMillis());
        //今天
        String cur = DateUtil.format(curDate, "yyyy-MM-dd");
        List<ViolationUser> todayViolationUser = violationUserMapper.getViolationUserInterval("1 day");
        EverydayVUCount everydayVUCount = everydayVUCountMapper.selectOne(
                new QueryWrapper<EverydayVUCount>().eq("time", cur));
        if(everydayVUCount == null){
            everydayVUCount = new EverydayVUCount();
            everydayVUCount.setTime(new Date());
            everydayVUCount.setCount(todayViolationUser.size());
            everydayVUCountMapper.insert(everydayVUCount);
        }else{
            everydayVUCount.setCount(todayViolationUser.size());
            everydayVUCountMapper.updateById(everydayVUCount);
        }

        log.info("已完成每日违规用户聚合任务");


        return ReturnT.SUCCESS;
    }

    @XxlJob("blackUserGroupJobHandler")
    public ReturnT<String> executeBlackGroup(String s) throws Exception{
        log.info("开始执行每日黑名单用户聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        //今天
        String curDateTime = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        String curDay = DateUtil.format(curDate, "yyyy-MM-dd");
        List<KindUser> todayBlackUser = kindUserMapper.selectList(
                new QueryWrapper<KindUser>()
                        .eq("black_or_white", "black")
                        .gt("create_time", curDateTime));
        BlackUserPromote todayPromote = blackUserPromoteMapper.selectOne(
                new QueryWrapper<BlackUserPromote>().eq("time", curDay));
        if(todayPromote == null){
            todayPromote = new BlackUserPromote();
            todayPromote.setTime(curDate);
            todayPromote.setCount(todayBlackUser.size());
            blackUserPromoteMapper.insert(todayPromote);
        }else{
            if(!todayPromote.getCount().equals(todayBlackUser.size())){
                todayPromote.setCount(todayBlackUser.size());
                blackUserPromoteMapper.updateById(todayPromote);
            }
        }
        log.info("已完成每日黑名单用户聚合任务");

        return ReturnT.SUCCESS;
    }

    @XxlJob("useTimeGroupJobHandler")
    public ReturnT<String> executeUseTimeGroup(String s) throws Exception{
        log.info("开始执行每日用户使用时长聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        //今天
        String curDateTime = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        String curDay = DateUtil.format(curDate, "yyyy-MM-dd");
        Map<String,String> useTimeMap = redisService.hGetAll("use_time_map");
        int userCount = useTimeMap.size();
        long allUseTime = 0L;
        for(String uid : useTimeMap.keySet()){
            allUseTime += Long.valueOf(useTimeMap.get(uid));
            redisService.hDelByKey("use_time_map", uid);
        }
        long avgUseTime = allUseTime / userCount;
        UserUseTime userUseTime = userUseTimeMapper.selectOne(
                new QueryWrapper<UserUseTime>().eq("time",curDay));
        if(userUseTime == null){
            userUseTime = new UserUseTime();
            userUseTime.setTime(new Date());
            userUseTime.setUseTime(avgUseTime / 60000.0);
            userUseTimeMapper.insert(userUseTime);
        }else{
            userUseTime.setUseTime(avgUseTime / 60000.0);
            userUseTimeMapper.updateById(userUseTime);
        }

        log.info("已完成每日用户使用时长聚合任务");
        return ReturnT.SUCCESS;
    }

    @XxlJob("violationTypeGroupJobHandler")
    public ReturnT<String> executeviolationTypeGroup(String s) throws Exception{
        log.info("开始执行每日用户使用时长聚合任务");
        List<ViolationUser> todayViolationUsers = violationUserMapper.getViolationUserInterval("1 day");
        Map<String, Long> typeCountMap = todayViolationUsers.stream()
                .collect(Collectors.groupingBy(ViolationUser::getViolationType, Collectors.counting()));

        List<ViolationUserType> allTypes = violationUserTypeMapper.selectList(new QueryWrapper<>());
        allTypes.forEach(item -> {
            item.setCount(item.getCount() + typeCountMap.getOrDefault(item.getViolationType(), 0L));
            violationUserTypeMapper.updateById(item);
        });

        log.info("已完成每日违规用户类型数量聚合任务");

        return ReturnT.SUCCESS;
    }

    @XxlJob("safeScoreGroupJobHandler")
    public ReturnT<String> executesafeScoreGroup(String s) throws Exception{
        log.info("开始执行全站用户平均安全得分聚合任务");
        List<BankUser> bankUsers = bankUserMapper.selectList(
                new QueryWrapper<BankUser>().eq("user_type", 0));
        BankUser admin = bankUserMapper.selectOne(
                new QueryWrapper<BankUser>().eq("user_type", 1));
        long scoreSum;
        long userCount = bankUsers.size();
        scoreSum = bankUsers.stream().mapToLong(BankUser::getSafeScore).sum();
        if(!admin.getSafeScore().equals((int)(scoreSum / userCount))){
            admin.setSafeScore((int) (scoreSum / userCount));
            bankUserMapper.updateById(admin);
        }

        log.info("已完成执行全站用户平均安全得分聚合任务");
        return ReturnT.SUCCESS;
    }

    @XxlJob("dayRemoteLoginJobHandler")
    public ReturnT<String> executeDayRemoteLoginGroup(String s) throws Exception{
        log.info("开始执行每日异地登陆次数聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        //今天
        String cur = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        String today = DateUtil.format(curDate, "yyyy-MM-dd");
        List<RemoteLoginEvent> events = remoteLoginEventMapper.selectList(
                new QueryWrapper<RemoteLoginEvent>().gt("create_time",cur ));
        int todayRemoteLoginCount = events.size();
        RemoteLoginFreq remoteLoginFreq = remoteLoginFreqMapper.selectOne(
                new QueryWrapper<RemoteLoginFreq>().eq("time", today));
        if(remoteLoginFreq == null){
            remoteLoginFreq = new RemoteLoginFreq();
            remoteLoginFreq.setTime(curDate);
            remoteLoginFreq.setCount(todayRemoteLoginCount);
            remoteLoginFreqMapper.insert(remoteLoginFreq);
        }else{
            if(!remoteLoginFreq.getCount().equals(todayRemoteLoginCount)){
                remoteLoginFreq.setCount(todayRemoteLoginCount);
                remoteLoginFreqMapper.updateById(remoteLoginFreq);
            }
        }
        log.info("已完成执行每日异地登陆次数合任务");
        return ReturnT.SUCCESS;
    }

    @XxlJob("monthRemoteLoginJobHandler")
    public ReturnT<String> executeMonthRemoteLoginGroup(String s) throws Exception{
        log.info("开始执行每月异地登陆次数聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        int month = DateUtil.month(curDate) + 1;
        int year = DateUtil.year(curDate);

        List<RemoteLoginFreq> freqs = remoteLoginFreqMapper.getRemoteLoginFreqInterval("1 month");
        long sum = freqs.stream().mapToLong(RemoteLoginFreq::getCount).sum();
        MonthRemoteLogin monthRemoteLogin = monthRemoteLoginMapper.selectOne(
                new QueryWrapper<MonthRemoteLogin>()
                        .eq("month",month)
                        .eq("year", year));
        if(monthRemoteLogin == null){
            monthRemoteLogin = new MonthRemoteLogin();
            monthRemoteLogin.setCount(sum);
            monthRemoteLogin.setYear(year);
            monthRemoteLogin.setMonth(month);
            monthRemoteLoginMapper.insert(monthRemoteLogin);
        }else{
            if(!monthRemoteLogin.getCount().equals(sum)){
                monthRemoteLogin.setCount(sum);
                monthRemoteLoginMapper.updateById(monthRemoteLogin);
            }
        }
        log.info("已完成执行每月异地登陆次数合任务");
        return ReturnT.SUCCESS;
    }


    @XxlJob("sensitiveTradingJobHandler")
    public ReturnT<String> executeSensitiveTradingGroup(String s) throws Exception{
        log.info("开始执行每日敏感交易量聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        String today = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        List<UserCapitalFlow> todaySensitiveFlow = userCapitalFlowMapper
                .selectList(new QueryWrapper<UserCapitalFlow>()
                        .gt("create_time", today)
                        .eq("is_sensitive", 1));
        double sensitiveMoney = todaySensitiveFlow.stream()
                .mapToDouble(UserCapitalFlow::getMoney).sum();
        SensitiveTrading todaySensitiveMoneyFlow = sensitiveTradingMapper.selectOne(
                new QueryWrapper<SensitiveTrading>().eq("time", today));
        if(todaySensitiveMoneyFlow == null){
            todaySensitiveMoneyFlow = new SensitiveTrading(curDate, sensitiveMoney, "");
            sensitiveTradingMapper.insert(todaySensitiveMoneyFlow);
        }else{
            if(!todaySensitiveMoneyFlow.getCount().equals(sensitiveMoney)){
                todaySensitiveMoneyFlow.setCount(sensitiveMoney);
                sensitiveTradingMapper.updateById(todaySensitiveMoneyFlow);
            }
        }
        log.info("已完成执行每日敏感交易量合任务");
        return ReturnT.SUCCESS;
    }


    @Resource
    private AbnormalUserMapper abnormalUserMapper;

    @Resource
    private EverydayAccountAbnormalMapper accountAbnormalMapper;

    @XxlJob("abnormalUserGroupJobHandler")
    public ReturnT<String> executeAbnormalUserGroup(String s) throws Exception{
        log.info("开始执行每日异常用户数量聚合任务");
        Date curDate = new Date(System.currentTimeMillis());
        String today = DateUtil.format(curDate, "yyyy-MM-dd 00:00:00");
        String todayDate = DateUtil.format(curDate, "yyyy-MM-dd");
        List<AbnormalUser> todayAbnormalUser = abnormalUserMapper.selectList(
                new QueryWrapper<AbnormalUser>().gt("create_time", today));
        int count = todayAbnormalUser.size();
        EverydayAccountAbnormal accountAbnormal = accountAbnormalMapper.selectOne(
                new QueryWrapper<EverydayAccountAbnormal>().eq("time", todayDate));
        if(accountAbnormal == null){
            accountAbnormal = new EverydayAccountAbnormal();
            accountAbnormal.setCount(count);
            accountAbnormal.setTime(curDate);
            accountAbnormalMapper.insert(accountAbnormal);
        }else{
            if(!accountAbnormal.getCount().equals(count)){
                accountAbnormal.setCount(count);
                accountAbnormalMapper.updateById(accountAbnormal);
            }
        }
        log.info("已完成每日异常用户数量聚合任务");
        return ReturnT.SUCCESS;
    }

    @XxlJob("userBalanceGroupJobHandler")
    public ReturnT<String> executeUserBanalceGroup(String s) throws Exception{
        log.info("开始执行每日用余额聚合任务");
        List<BankUser> bankUsers = bankUserMapper.selectList(new QueryWrapper<>());
        List<UserBalance> todayUserBalance = new ArrayList<>();
        bankUsers.forEach(item -> {
            UserBalance balance = userBalanceMapper.selectOne(
                    new QueryWrapper<UserBalance>()
                            .eq("time", formatter2.format(new Date()))
                            .eq("uid", item.getId()));
            if(balance == null){
                balance = new UserBalance();
                balance.setBalance(item.getMoney());
                balance.setTime(formatter2.format(new Date()));
                balance.setUid(item.getId());
                userBalanceMapper.insert(balance);
            }else{
                balance.setBalance(item.getMoney());
                userBalanceMapper.updateById(balance);
            }
        });
        log.info("已完成执行每日用余额聚合任务");
        return ReturnT.SUCCESS;
    }
}
